package cn.shadow.service;

import cn.shadow.bean.PlayerModule;
import cn.shadow.bean.UserInfo;
import cn.shadow.concurrent.DisruptorExecutor;
import cn.shadow.entity.Player;
import cn.shadow.mapper.UserMapper;
import cn.shadow.entity.ConnectedUser;
import cn.shadow.entity.User;
import cn.shadow.message.MessageWorker;
import cn.shadow.module.login.LoginModuleMessages;
import cn.shadow.moulde.ISender;
import cn.shadow.proto.server.PlayerBasicServerProtoContent.*;
import cn.shadow.proto.server.PlayerServerProtoContent.*;
import cn.shadow.utils.*;
import com.google.protobuf.InvalidProtocolBufferException;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.List;

@Service
@Data
@Slf4j
public class UserService {

    final UserMapper userMapper;

    final Services services;


    @Autowired(required = false)
    public UserService(UserMapper userMapper, Services services) {
        this.userMapper = userMapper;
        this.services = services;
    }


    public void processCreateOrLoginByName(ByteBuf buffer, MessageWorker worker) {
        //IP被ban掉了
        final long ctime = services.getITimeService().getCurrentTime();
        final String username = BufferUtil.readUTF(buffer);
        services.getIThreadService().getDbExecutor().execute(() -> {
            final byte[] usernameBytes;
            final int operatorID; //运营商id
            final int serverID; //区服id
            //username是由平台id+区服id+用户名
            String[] parts = username.split("-");
            if (parts.length == 3) {
                operatorID = Integer.parseInt(parts[0]);
                serverID = Integer.parseInt(parts[1]);
                usernameBytes = StringEncoder.encode(parts[2]);
            } else if (parts.length == 1) {
                operatorID = services.getConfigService().getOperatorID();
                serverID = services.getConfigService().getServerID();
                usernameBytes = StringEncoder.encode(parts[0]);
            } else {
                log.error("登录时, 名字中有 - 号, 必须是 运营商id-区服id-用户id");
                return;
            }
            String useName = StringEncoder.encode(usernameBytes);
            Long playerId = userMapper.getUserIdByUserName(useName, serverID, operatorID);
            if (playerId != null) {
                tryLoginByPlayId(playerId, ctime, worker);
            } else {
                tryFirstLogin(usernameBytes, serverID, operatorID, worker);
            }
        });
    }

    /**
     * 第一次登录进来
     */
    private void tryFirstLogin(byte[] usernameBytes, int serverID, int operatorID, MessageWorker worker) {
        String name = StringEncoder.encode(usernameBytes);
        if (!NameHelper.isValidUserName(name)) {
            log.error("无效的账号");
            return;
        }
        long ctime = services.getITimeService().getCurrentTime();
        UserInfo userInfo = new UserInfo(null, serverID, operatorID, ctime, ctime, name, null, null, null, null);
        userMapper.createUser(userInfo);
        //插入成功
        Integer id = userInfo.getId();//获得最新的自增id
        if (id != null) { //设置最新的userId
            long playerId = IDUtils.combineUserAndServerAndOperatorID(id, serverID, operatorID);
            userMapper.updatePlayId(playerId, id, serverID, operatorID);
            User user = new User(id, serverID, operatorID, ctime, name);
            tryLoginByPlayId(user.getPlayerId(), ctime, worker);
        } else {
            log.error("玩家登录失败");
        }

    }

    private void tryLoginByPlayId(long playerId, long ctime, MessageWorker worker) {
        ConnectedUser cu = services.getWorldService().getUser(playerId);
        if (cu != null) {
            log.error("在其他地方登录");
            return;
        }
        //用户线程从db线程去获取
        DisruptorExecutor executor = services.getIThreadService().getExecutor(IDUtils.getUserID(playerId));
        executor.execute(() -> {
            User user = getOrCreateUserByID(playerId, worker);
            if (user == null) {
                log.error("竟然返回了空值");
                return;
            }
            ConnectedUser connectedUser = new ConnectedUser(user);
            //尝试将连接对象放置进入map中
            WorldService worldService = services.getWorldService();
            worker.setTaskExc(executor);//将work的线程处理者设置为它
            if (worldService.addConnectedUser(connectedUser) == null) {
                worker.setConnectedUser(connectedUser); //将对象放入worldService，完成登录
                Player player = user.getPlayer();
                if (player != null) {
                    log.info("用户角色添加成功：" + user.getPlayer());
                    playerDoStart(player, connectedUser);
                    worker.getChannelSender().sendMessage(LoginModuleMessages.createResultBuffer(2));
                    worker.getChannelSender().sendMessage(LoginModuleMessages.createPlayerSucceed(player.encode4Server(ctime).toByteArray()));
                } else {
                    worker.getChannelSender().sendMessage(LoginModuleMessages.createResultBuffer(1));
                }
            }
        });


    }


    private User getOrCreateUserByID(long playerId, MessageWorker worker) {
        UserInfo userInfo = new UserInfo();
        userInfo.setPlayerId(playerId);
        List<UserInfo> select = userMapper.select(userInfo);
        if (select == null || select.isEmpty()) {
            int id = IDUtils.getUserID(playerId);
            long ctime = services.getITimeService().getCurrentTime();
            userInfo = new UserInfo(null, IDUtils.getServerID(id), IDUtils.getOperatorID(playerId), ctime, ctime, "", playerId, null, null, null);
            userMapper.createUser(userInfo);
            return new User(playerId, ctime, "");
        }
        userInfo = select.get(0);
        User user = new User();
        BeanUtils.copyProperties(userInfo, user);
        byte[] playerData = userInfo.getPlayerData();
        String playerName = userInfo.getPlayerName();
        if (playerName != null) {
            try {
                PlayerServerProto playerProto = PlayerServerProto.parseFrom(playerData);
                user.decodePlayer(playerProto, worker.getChannelSender());
            } catch (InvalidProtocolBufferException e) {
                e.printStackTrace();
            }
        }
        return user;
    }

    /**
     * 创建玩家角色
     */
    public void processCreatePlayer(ByteBuf buffer, int sequenceID, MessageWorker worker) {
        if (sequenceID == LoginModuleMessages.C2S_CREATE_PLAYER) {
            User user = worker.getConnectedUser().getUser();
            if (user.getPlayer() != null) {
                log.error("已经创建过角色了，无需再请求");
                return;
            }
            worker.getTaskExc().execute(() -> { //用户线程执行创建角色
                boolean isMale = BufferUtil.readBoolean(buffer);
                String playerName = BufferUtil.readUTF(buffer);
                //判断heroName是否在redis里面，如果在就返回错误信息
                Object result = createPlayer(user, worker.getChannelSender(), playerName, isMale, true);
                if (result instanceof Integer) {
                    log.info("创建角色失败错误码：{}", result);
                }
                if (result instanceof Player) { //返回角色对象，创建成功
                    Player player = (Player) result;
                    user.setPlayer(player);
                    //角色已经创建完毕,执行初始化的操作
                    playerDoStart(player, worker.getConnectedUser());
                    //发送创建成功消息
                    log.info("角色创建成功-{}", player.toString());
                    long ctime = services.getITimeService().getCurrentTime();
                    worker.getChannelSender().sendMessage(LoginModuleMessages.createPlayerSucceed(player.encode4Client(ctime).toByteArray()));
                }
            });
        }
    }

    /**
     * 用户用这个角色开始游戏
     */
    private void playerDoStart(Player player, ConnectedUser connectedUser) {
        PlayerModule playerModule = new PlayerModule(services, player);
        connectedUser.setPlayerModule(playerModule);
        log.info("角色模型已经创建,可以处理任何消息了");
    }

    private Object createPlayer(User user, ISender sender, String playerName, boolean ismale, boolean checkPlayerName) {
        if (checkPlayerName && !NameHelper.isValidPlayerName(playerName)) {
            return CreatePlayerCode.ERR_CREATE_PLAYER_ILLEGAL_CHAR.code();
        }
        long ctime = services.getITimeService().getCurrentTime();
        PlayerServerProto.Builder serverBuilder = PlayerServerProto.newBuilder();
        PlayerBasicServerProto.Builder basicBuilder = PlayerBasicServerProto.newBuilder();
        basicBuilder.setId(user.getPlayerId()).setName(playerName).setIsMale(ismale).setCreateTime(ctime).setUserName(user.getUsername());
        serverBuilder.setBasic(basicBuilder);
        Player player = new Player(serverBuilder.build(), sender);
        byte[] playerData = player.encode4Server(ctime).toByteArray();
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(user, userInfo);
        userInfo.setPlayerData(playerData);
        userInfo.setPlayerCreateTime(ctime);
        userInfo.setPlayerName(playerName);
        Example example = new Example(UserInfo.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("playerId", user.getPlayerId());
        int result = userMapper.updateByExampleSelective(userInfo, example);
        if (result > 0) {
            return player;
        }
        return CreatePlayerCode.ERR_CREATE_PLAYER_WRONG;
    }


    enum CreatePlayerCode {
        ERR_CREATE_PLAYER_WRONG(1, "未能创建角色"),

        ERR_CREATE_PLAYER_ILLEGAL_CHAR(2, "昵称非法字符");
        int code;
        String msg;

        CreatePlayerCode(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        public int code() {
            return code;
        }
    }


}
